package com.delayqueue.core.permanent.executor;

import com.alibaba.fastjson.JSON;
import com.delayqueue.common.task.Task;
import com.delayqueue.core.common.FileUtil;
import com.delayqueue.core.common.TimeUtil;
import com.delayqueue.core.permanent.PermanentConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Vector;

@Slf4j
@Component
public class PermanentArchiveExecutor implements PermanentExecutor, DisposableBean {

    @Autowired
    private PermanentConfig permanentConfig;
    private FileOutputStream outputStream;
    private File currentWriteFile;

    private Vector<byte[]> tempWriteQueue;
    private boolean isPause = false;


    @PostConstruct
    protected void initArchive() {
        if (permanentConfig.getArchive() && outputStream == null) {
            File dir = new File(permanentConfig.getArchiveDirPath());
            if (!dir.exists()) {
                dir.mkdirs();
            }
            currentWriteFile = getLastFile();
            try {
                outputStream = new FileOutputStream(currentWriteFile, true);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void execute(Task task) {
        if (task != null) {
            String json = JSON.toJSONString(task);
            json += "\r\n";
            writeArchive(json.getBytes(StandardCharsets.UTF_8));
        }
    }

    private void writeArchive(byte[] bytes) {
        try {
            if (!isPause) {
                outputStream.write(bytes);
                if (currentWriteFile.length() >= permanentConfig.getArchiveMaxFileSize()) {
                    tempWriteQueue = new Vector<>();
                    isPause = true;
                    archiveChangeFile();
                    isPause = false;
                    Iterator<byte[]> iterator = tempWriteQueue.iterator();
                    while (iterator.hasNext()) {
                        outputStream.write(iterator.next());
                    }
                    tempWriteQueue.clear();
                    tempWriteQueue = null;
                }
            } else {
                tempWriteQueue.add(bytes);
            }
        } catch (IOException e) {
            log.error("写入archive出错：", e);
        }
    }


    public void archiveChangeFile() {
        currentWriteFile = newArchiveFile();
        try {
            outputStream.flush();
            outputStream.close();
            outputStream = null;
            outputStream = new FileOutputStream(currentWriteFile, true);
        } catch (IOException e) {
            log.error("archive文件切换出错：", e);
        }
    }

    private File newArchiveFile() {
        File dir = new File(permanentConfig.getArchiveDirPath());
        File[] files = dir.listFiles();
        String fileName = TimeUtil.format("yyyy-MM-dd-HH-mm");
        int fileNum = 0;
        for (File file : files) {
            String name = file.getName();
            if (name.startsWith(fileName)) {
                int num = Integer.parseInt(name.substring(name.lastIndexOf("_") + 1));
                if (num > fileNum) {
                    fileNum = num;
                }
            }
        }
        fileNum++;
        File file = new File(permanentConfig.getArchiveDirPath() + "/" + fileName + "_" + fileNum);
        FileUtil.createFileIfNotExisis(file);
        return file;
    }

    private File getLastFile() {
        File dir = new File(permanentConfig.getArchiveDirPath());
        File[] files = dir.listFiles();
        if (files.length == 0) {
            File file = new File(permanentConfig.getArchiveDirPath() + "/" + TimeUtil.format("yyyy-MM-dd-HH-mm") + "_1");
            FileUtil.createFileIfNotExisis(file);
            return file;
        } else {
            String maxTime = "";
            int maxNum = 0;
            for (File file : files) {
                String name = file.getName();
                String time = name.substring(0, name.lastIndexOf("_"));
                int num = Integer.parseInt(name.substring(name.lastIndexOf("_") + 1));
                if (time.equals(maxTime)) {
                    if (num > maxNum) {
                        maxNum = num;
                    }
                } else if (time.compareTo(maxTime) > 0) {
                    maxTime = time;
                    maxNum = num;
                }
            }
            return new File(permanentConfig.getArchiveDirPath() + "/" + maxTime + "_" + maxNum);
        }
    }

    @Override
    public void destroy() throws Exception {

        if (outputStream != null) {
            outputStream.flush();
            outputStream.close();
            outputStream = null;
        }
    }

}
